#ifndef _HW_SPIFLASH_DRIVER_
#define _HW_SPIFLASH_DRIVER_

#include "sys_config.h"
#include "sys_types.h"

#define FLASH_SIZE   0x00080000	// 4M bits

#define KBYTES  1024
#define MBYTES  (1024*KBYTES)

#define FLASH_READ_UNIT	4

// -------------------------------
// FLASH Mapping
// -------------------------------
#define NUMBER_OF_BANKS 1
#define BANK0_BASE      0




// Get the page number from the _physical_ flash address
#define GET_PAGE_PHYS(PhysAddr)  (UINT8)(((UINT32)PhysAddr >> 19) & 0x7)



#define MREAD_8(addr) *((volatile UINT8 *)(addr))
#define MWRITE_8(addr,data) *((volatile UINT8 *)(addr)) = data

#define MREAD_16(addr) *((volatile UINT16 *)(addr))
#define MWRITE_16(addr,data) *((volatile UINT16 *)(addr)) = data

#define MREAD_32(addr) *((volatile UINT32 *)(addr))
#define MWRITE_32(addr,data)  { *((volatile UINT32 *)(addr)) = data; }



#define SPI_FLASH_REG_BASE 0x40130000
#define CMD_ADDR_OFFSET 0x0
#define MODE_BLOCKSIZE_OFFSET 0x4
#define DATA_FIFO_OFFSET 0x8
#define STATUS_OFFSET 0xc
#define READBACK_REG_OFFSET 0x10
#define FLASH_CONFIG_OFFSET 0x14
#define FIFO_CTRL_OFFSET 0x18
#define DUAL_SPI_OFFSET 0x1c
#define READ_CMD_OFFSET 0x20


#define OPCODE_WRITE_ENABLE 0x06
#define OPCODE_READ_STATUS 0x05
#define OPCODE_WRITE_STATUS 0x01
#define OPCODE_READ_STATUS_1 0x00
//0x32: cmd and addr need use one line to be send, data need use 4 lines to be send
//0x38: cmd need use one line to be send, addr and data need use 4 lines to be send
#define OPCODE_QUAD_PAGE_PROGRAM 0x32
#define OPCODE_BLOCK_ERASE_64K 0xd8
#define OPCODE_SECTOR_ERASE 0x20
#define OPCODE_CHIP_ERASE 0x60
#define OPCODE_READ_DATA 0x03
#define OPCODE_QUAD_FAST_READ 0xeb


#define OPCODE_SR_WRITE_ENABLE 0x50
#define OPCODE_RDSR 0x05
#define OPCODE_WRR 0x01
//#define OPCODE_RCR 0x35
#define OPCODE_QPP 0x32
#define OPCODE_SE 0xd8
#define OPCODE_P4E 0x20
#define OPCODE_BE 0x60
#define OPCODE_READ 0x03
#define OPCODE_QIQR 0xeb
//for test OPCODE_HIGH_P_MODE
//#define OPCODE_HIGH_P_MODE 0xff
#define OPCODE_RDI 0xab
#define OPCODE_DP 0xb9
#define OPCODE_HIGH_P_MODE 0xa3
#define OPCODE_ReadReset 0xff
#define OPCODE_PROGRAM_ERASE_SUSPEND 0xb0
#define OPCODE_PER 0x30

//#define OPCODE_BLOCK_ERASE_64K      0x20    // sector erase

#define OPCODE_REMS    0x90    // read manufacture/device ID 
#define OPCODE_RDID    0x9f    // read identification
#define OPCODE_BE_1    0x52    // 32KB block erase
#define OPCODE_BE_2    0xd8    // 64kB block erase
#define SECTOR_SIZE    0x1000	//sector size is 4K

#define OPCODE_ENQPI  0x35
#define OPCODE_DISABLEQPI   0xf5
#define OPCODE_ENRST  0x66
#define OPCODE_RST      0x99



// SPI FLASH INTERFACE

#define OPCODE_WRITE_STATUS_VOLATILE 0x81
#define OPCODE_READ_STATUS_VOLATILE 0x85
#define SPI_CMD_ADDR (SPI_FLASH_REG_BASE+CMD_ADDR_OFFSET)
#define SPI_BLOCK_SIZE (SPI_FLASH_REG_BASE+MODE_BLOCKSIZE_OFFSET)
#define SPI_DATA_FIFO (SPI_FLASH_REG_BASE+DATA_FIFO_OFFSET)
#define SPI_STATUS (SPI_FLASH_REG_BASE+STATUS_OFFSET)
#define SPI_READ_BACK (SPI_FLASH_REG_BASE+READBACK_REG_OFFSET)
#define SPI_CONFIG (SPI_FLASH_REG_BASE+FLASH_CONFIG_OFFSET)
#define SPI_FIFO_CTRL (SPI_FLASH_REG_BASE+FIFO_CTRL_OFFSET)
#define SPI_CS_SIZE (SPI_FLASH_REG_BASE+DUAL_SPI_OFFSET)
#define SPI_READ_CMD (SPI_FLASH_REG_BASE+READ_CMD_OFFSET)

#define SPI_CMD_ADDR_REG (SPI_FLASH_REG_BASE+CMD_ADDR_OFFSET)
#define SPI_FLASH_TX_COMMAND_BIT    0
#define SPI_FLASH_TX_ADDRESS_BIT    8
#define SPI_FLASH_TX_CMD_SPD_ID_BIT     0
#define SPI_FLASH_TX_COMMAND_BIT_SPD_MODE   8
#define SPI_FLASH_TX_CMD_RW_FLAG_BIT    16
#define SPI_FLASH_TX_SPI_MODE_FLAG_BIT      17
#define SPI_FLASH_CMD_ADDR_REG_RESERVED_BIT     18

#define SPI_BLOCK_SIZE_REG (SPI_FLASH_REG_BASE+MODE_BLOCKSIZE_OFFSET)
#define SPI_FLASH_MODEBIT_BIT   0
#define SPI_FLASH_RW_SIZE_BIT   8   
#define SPI_FLASH_BLOCK_SIZE_REG_RESERVED_BIT   17

#define SPI_DATA_FIFO_REG (SPI_FLASH_REG_BASE+DATA_FIFO_OFFSET)
#define SPI_TX_DATA_FIFO_BIT 0
#define SPI_DATA_FIFO_REG_RESERVED_BIT  8
#define SPI_TX_DATA_FIFO_BIT_SPD_MODE     0
#define SPI_DATA_SEND_TYPE_BIT_SPD_MODE       8
#define SPI_DATA_FIFO_REG_RESERVED_BIT_SPD_MODE     8

#define SPI_STATUS_REG (SPI_FLASH_REG_BASE+STATUS_OFFSET)
#define SPI_BUSY_BIT      0
#define SPI_TX_FIFO_EMPTY_BIT   1
#define SPI_TX_FIFO_FULL_BIT     2
#define SPI_RX_FIFO_EMPTY_BIT   3
#define SPI_RX_FIFO_COUNT_BIT   4
#define SPI_STATUS_REG_RESERVED_BIT     9

#define SPI_READ_BACK_REG (SPI_FLASH_REG_BASE+READBACK_REG_OFFSET)
#define SPI_RAED_BACK_DATA_BIT 0

#define SPI_CONFIG_REG (SPI_FLASH_REG_BASE+FLASH_CONFIG_OFFSET)
#define SPI_READ_MODE_FLAG_BIT      0
#define SPI_PROTECT_PIN_BIT              1
#define SPI_HOLD_PIN_BIT                    2
#define SPI_SAMPLE_DATA_DELAY_CYCLE_BIT 4
#define SPI_CLK_DIVIDER_BIT               8
#define SPI_COMMAND_SEND_QUAD_LINES_BIT     16  
#define SPI_CONFIG_REG_RESERVED_BIT             17

#define SPI_FIFO_CTRL_REG (SPI_FLASH_REG_BASE+FIFO_CTRL_OFFSET)
#define SPI_RX_FIFO_CLR_BIT         0
#define SPI_TX_FIFO_CLR_BIT         1
#define SPI_FIFO_CTRL_REG_RESERVED_BIT      2

#define SPI_CS_SIZE_REG (SPI_FLASH_REG_BASE+DUAL_SPI_OFFSET)
#define SPI_FLASH_NUMS_USED_BIT     0
#define SPI_FLASH_SIZE_USED_BIT     1
#define SPI_CS_SIZE_REG_RESERVED_BIT    2

#define SPI_READ_CMD_REG (SPI_FLASH_REG_BASE+READ_CMD_OFFSET)
#define SPI_QUAD_READ_CMD_RECFG_BIT     0   
#define SPI_FAST_READ_CMD_RECFG_BIT     8
#define SPI_PROTECT_BYTE_BIT                    24




/*****************************************************************/
//	FLASH_TYPE_ID = 0 : normal flash
//	FLASH_TYPE_ID = 1 : x25u3235e
//	FLASH_TYPE_ID = 2 : en25q32
/*****************************************************************/
#define FLASH_TYPE_ID   0
#define TOTAL_FLASH_ID  3


typedef int BOOL;
typedef u_int32 UINT32;
typedef u_int16 UINT16;
typedef u_int8 UINT8;



// =============================================================================
//  MEMD_ERR_T
// -----------------------------------------------------------------------------
/// Error codes
/// The Flash API uses the following error codes. 
/// Those errors reflect errors from the flash chip, for consistency the current 
/// operation should be restarted.
// =============================================================================
typedef enum
{
    /// No error occured
    MEMD_ERR_NO = 0,

    /// An error occurred during the erase operation
    MEMD_ERR_ERASE ,

    /// An error occurred during the write operation
    MEMD_ERR_WRITE,

    /// This error occurs when a command requiring 
    /// sector aligned addresses as parameters is called with unaligned addresses. 
    /// (Those are 
    /// #memd_FlashErrors memd_FlashErase, #memd_FlashLock and #memd_FlashUnlock)
    MEMD_ERR_ALIGN,

    /// An erase or write operation was attempted on a protected sector
    MEMD_ERR_PROTECT,
    /// erase suspend.
    MEMD_ERR_SUSPEND
    
}MEMD_ERR_T;

typedef enum
{
    MEMD_FLASH_SPANSION = 0x01,
    MEMD_FLASH_EON = 0x1c,
    MEMD_FLASH_MXIC = 0xc2, 
    MEMD_FLASH_GIGADEVICE = 0xc8,   
    MEMD_FLASH_BERGMICRO = 0xe0, 
    MEMD_FLASH_WINBOND = 0xef,
    MEMD_FLASH_FIDELIX = 0xf8,
    MEMD_FLASH_ESMT = 0x8c,
    MEMD_FLASH_NUMONYX = 0x20,
    MEMD_FLASH_MICRON = 0x2c,
    MEMD_FLASH_PM25L = 0x7f,
    MEMD_FLASH_FUDAN = 0xa1   
}MEMD_FLASH_MANUFACTURER_T;

typedef enum
{
    MEMD_FLASH_SPANSION_30V = 0x02,
    MEMD_FLASH_EON_30V = 0x30,
	MEMD_FLASH_EON_18V = 0x38,
	MEMD_FLASH_MXIC_30V = 0x5E, 
	MEMD_FLASH_MXIC_18V = 0x25, 
    MEMD_FLASH_GIGADEVICE_30V = 0x40,
    MEMD_FLASH_GIGADEVICE_18V = 0x60,  
	MEMD_FLASH_WINBOND_30V = 0x40,
	MEMD_FLASH_WINBOND_18V = 0x60,
    MEMD_FLASH_FIDELIX_30V = 0x32,
	MEMD_FLASH_FIDELIX_18V = 0x42,
	MEMD_FLASH_ESMT_30V = 0x41,
	MEMD_FLASH_ESMT_18V = 0x25,
    MEMD_FLASH_NUMONYX_30V = 0xBA,    
    MEMD_FLASH_MICRON_18V = 0xCB,
    MEMD_FLASH_FUDAN_30V = 0x40
}MEMD_FLASH_MEMORY_TYPE_T;

typedef enum
{
    MEMD_FLASH_SPANSION_64M = 0x16,
    MEMD_FLASH_EON_64M = 0x17,
    MEMD_FLASH_EON_32M = 0x16,
    MEMD_FLASH_MXIC_U_128M = 0x38, 
	MEMD_FLASH_MXIC_U_64M = 0x37,
	MEMD_FLASH_MXIC_U_32M = 0x36, 
	MEMD_FLASH_MXIC_L_32M = 0x16, 	
    MEMD_FLASH_GIGADEVICE_64M = 0x17,  
    MEMD_FLASH_GIGADEVICE_32M = 0x16,
    MEMD_FLASH_GIGADEVICE_128M = 0x18,
    MEMD_FLASH_GIGADEVICE_256M = 0x19,
	MEMD_FLASH_WINBOND_64M = 0x17,
	MEMD_FLASH_WINBOND_32M = 0x16,
    MEMD_FLASH_FIDELIX_64M = 0x17,   
    MEMD_FLASH_FIDELIX_32M = 0x16,
    MEMD_FLASH_ESMT_64M_30V = 0x17,
    MEMD_FLASH_ESMT_32M_30V = 0x16,
    MEMD_FLASH_ESMT_64M_18V = 0x37,
    MEMD_FLASH_ESMT_32M_18V = 0x36,
    MEMD_FLASH_NUMONYX_128M = 0x18,
    MEMD_FLASH_MICRON_32M = 0x16,
    MEMD_FLASH_MICRON_64M = 0x17,
    MEMD_FLASH_MICRON_128M = 0x18,
    MEMD_FLASH_FUDAN_32M = 0x16
}MEMD_FLASH_CAPACITY_TYPE_T;


typedef struct
{     
    MEMD_FLASH_MANUFACTURER_T manufacturerID;  
	MEMD_FLASH_MEMORY_TYPE_T device_memory_type_ID;
	MEMD_FLASH_CAPACITY_TYPE_T device_capacity_type_ID;
} MEMD_SPIFLSH_RDID_T;


typedef struct
{ 
    /// Start address of the bank
    UINT32 bankStartAddr;

    /// Composition of the bank, which can be made of up to 3 different sector
    /// types. One line is for one sector type. The first column is the number
    /// of sectors of this type and the second column is the size of this type
    /// of sector.
    UINT32 sectorLayoutTable[3][2];

} MEMD_BANK_LAYOUT_T;


// =============================================================================
// MEMD_FLASH_LAYOUT_T
// -----------------------------------------------------------------------------
/// This structure describes a flash through its different banks.
// =============================================================================
typedef struct
{
    /// Number of banks in the flash
     UINT8 numberOfBank;

    /// Table of pointers to the structures describing the different banks
     MEMD_BANK_LAYOUT_T* bankLayout;
    
    /// Size of the flash in bytes.
     UINT32 fullSize;
    
    /// User Data Field Base Address
     UINT32 userDataBase;
    
    /// User Data Field Size
     UINT32 userDataSize;

    /// User Data Sector Logical Block Size
     UINT32 userDataSectorLogicalBlockSize;
} MEMD_FLASH_LAYOUT_T;





MEMD_ERR_T memd_FlashRead(UINT8 *flashAddress,UINT32  byteSize,UINT32* pReadByteSize,UINT8*  buffer);
MEMD_ERR_T memd_FlashWrite(UINT8 *flashAddress,UINT32 byteSize, UINT32 * pWrittenByteSize, UINT8* buffer);
BOOL spi_flash_chip_erase(UINT32 flash_addr);
BOOL spi_flash_block_erase(UINT32 flash_addr);
BOOL spi_flash_sector_erase(UINT32 flash_addr);
//BOOL spi_flash_sector_erase2(UINT32 flash_addr);
MEMD_ERR_T memd_FlashErase(UINT8 *startFlashAddress, UINT8 *endFlashAddress);


u_int8 HW_Flash_Head(u_int8* data);
u_int8 HW_Flash_Sequen_read(u_int32 addr,u_int8* data, u_int32 length);
u_int8 HW_Flash_Sequen_write(u_int32 addr,u_int8* data, u_int32  length);
BOOL HW_Flash_Erase(u_int8  flag,u_int32 addr);
void HW_Flash_Open_Clock();
void HW_Flash_Close_Clock();


u_int8 HW_Efuse_Write(u_int8* data);
void HW_Flash_Data_read(u_int32 addr,u_int8* data, u_int32 length,u_int8 flag);


#endif  // _HW_SPIFLASH_DRIVER_

